#pragma once 
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <unordered_map>
#include <sstream>
#include <fstream>
#include "Log.hpp"

using namespace std;
static const string sep = "\r\n";
static const string headersep = ": ";
static const string wwwroot = "wwwroot";
static const string home = "index.html";
static const string httpversion = "HTTP/1.0";
static const string space = " ";
static const string filesuffix = ".";

class HttpRequest
{
private:
    string GetOneline(string &reqstr)
    {
        if(reqstr.empty()) return reqstr;
        auto pos = reqstr.find(sep);
        if(pos == string::npos) return string();

        string line = reqstr.substr(0, pos);
        reqstr.erase(0, pos+sep.size());
        return line.empty() ? sep : line;
    }
    bool ParseHeaderHelper(const string &line, string *k, string *v)
    {
        auto pos = line.find(headersep);
        if(pos == string::npos) return false;

        *k = line.substr(0, pos);
        *v = line.substr(pos + headersep.size());
        return true;
    }
public:
    HttpRequest():_blank_line(sep), _path(wwwroot)
    {}
    void Serialize()
    {}
    void Derialize(string &reqstr)
    {
        _req_line = GetOneline(reqstr); // 拿到第一行
        while(true)
        {
            string line = GetOneline(reqstr);
            if(line.empty()) break;
            else if(line == sep)
            {
                _req_text = reqstr;
                break;
            }
            else 
            {
                _req_hander.emplace_back(line);
            }
        }
        ParseReqLine();
        ParseHeader();
    }
    void Print()
    {
        cout << "===" <<_req_line << endl;
        for(auto &hander:_req_hander)
        {
            cout << "***" << hander <<endl;
        }
        cout << _blank_line;
        cout << _req_text << endl;

        cout << "method ###" << _method << endl;
        cout << "url ###" << _url << endl;
        cout << "path ###" << _path << endl;
        cout << "version ###" << _version << endl;
        for(auto& header : _headers)
        {
            cout << "@@@" << header.first << " - "<< header.second << endl;
        }
    }
    bool ParseReqLine()
    {
        if(_req_line.empty()) return false;
        stringstream ss(_req_line);

        ss >> _method >> _url >> _version;
        _path += _url;

        // 判断一下是否请求了/
        if(_path[_path.size()-1] == '/')
        {
            _path += home;
        }
        auto pos = _path.rfind(filesuffix);
        if(pos == string::npos)
        {
            _suffix = ".unknown";
        }
        else 
        {
            _suffix = _path.substr(pos);
        }
        LOG(INFO, "client want get %s", _path.c_str());
        return true;
    }
    bool ParseHeader()
    {
        for(auto& header : _req_hander)
        {
            string k,v;
            if(ParseHeaderHelper(header, &k, &v))
            {
                _headers.insert(make_pair(k, v));
            }
        }
        return true;
    }
    string Path()
    {
        return _path;
    }
    string Suffix()
    {
        return _suffix;
    }
    ~HttpRequest()
    {}
private:
    // 原始协议内容
    string _req_line;
    vector<string> _req_hander;
    string _blank_line;
    string _req_text;
    
    // 期望解析的结果
    string _method;
    string _url;
    string _path;
    string _suffix;
    string _version; 
    unordered_map<string, string> _headers;
};

class HttpResponse
{
public:
    HttpResponse():_version(httpversion), _blank_line(sep)
    {}
    void AddStatusLine(int code, const string &desc)
    {
        _code = code;
        _desc = desc;
    }
    void AddHeader(const string &k, const string &v)
    {
        LOG(DEBUG, "AddHeader: %s->%s", k.c_str(), v.c_str());
        _headers[k] = v;
    }
    void AddText(string &text)
    {
        _resp_text = text;
    }
    string Serialize()
    {
        string _status_line = _version + space + to_string(_code) + space + _desc + sep;
        for(auto &heads : _headers)
        {
            _resp_hander.emplace_back(heads.first + headersep + heads.second + sep);
        }

        // 序列化
        string respstr = _status_line;
        for(auto &header : _resp_hander)
        {
            respstr += header;
        }
        respstr += _blank_line;
        respstr += _resp_text;
        return respstr;
    }   
    ~HttpResponse()
    {}
private:
    // 构建应答的必要字段
    int _code;
    string _version;
    string _desc;
    unordered_map<string, string> _headers;

    // 应答结构化字段
    string _status_line;
    vector<string> _resp_hander;
    string _blank_line;
    string _resp_text;
};

class Factory
{
public:
    static shared_ptr<HttpRequest> BuildHttpRequest()
    {
        return make_shared<HttpRequest>();
    }
    static shared_ptr<HttpResponse> BuildHttpResponse()
    {
        return make_shared<HttpResponse>();
    }
};

class HttpServer
{
public:
    HttpServer()
    {
        _mime_type.insert(make_pair(".html", "text/html"));
        _mime_type.insert(make_pair(".css", "text/css"));
        _mime_type.insert(make_pair(".js", "application/x-javascript"));
        _mime_type.insert(make_pair(".png", "image/png"));
        _mime_type.insert(make_pair(".jpg", "image/jpeg"));
        _mime_type.insert(make_pair(".unknown", "text/html"));
        _code_to_desc.insert(make_pair(100, "Continue"));
        _code_to_desc.insert(make_pair(200, "OK"));
        _code_to_desc.insert(make_pair(301, "Moved Permanently"));
        _code_to_desc.insert(make_pair(302, "Found"));
        _code_to_desc.insert(make_pair(500, "Internal Server Error"));
    }
    string ReadFileContent(const string &path, int *size)
    {
        // 按照二进制打开
        ifstream in(path, ios::binary);// 是ifstream!! 不是fstream！！
        if(!in.is_open())
        {
            return string();
        }
        in.seekg(0, in.end);
        int filesize = in.tellg();
        in.seekg(0, in.beg);

        string content;
        content.resize(filesize);
        in.read((char*)content.c_str(), filesize);

        in.close();
        *size = filesize;
        return content;
    }
    string HandlerHttpRequest(string req)
    {
#ifdef TEST
        cout << "-------------------------------"<<endl;
        cout << req;

        string response = "HTTP/1.0 200 OK\r\n";
        response += "\r\n";
        response += "<html><body><h1>hello world</h1></body></html>";
        return response;
#else
        auto request = Factory::BuildHttpRequest();
        request->Derialize(req);
        int contentsize = 0;
        string text = ReadFileContent(request->Path(), &contentsize);
        string suffix = request->Suffix();

        int code = 302;
        auto response = Factory::BuildHttpResponse();
        response->AddStatusLine(code, _code_to_desc[code]);
        response->AddHeader("Content-Length", to_string(contentsize));
        response->AddHeader("Content-Type", _mime_type[suffix]);
        response->AddHeader("Location", "https://www.qq.com/");
        // response->AddText(text);

        return response->Serialize();

#endif
    }
    ~HttpServer()
    {}
private:
    unordered_map<string, string> _mime_type;
    unordered_map<int , string> _code_to_desc;
};